package com.aihuishou.monitor.url;

import com.aihuishou.monitor.LogConstants;
import com.aihuishou.monitor.LogMonitor;
import com.aihuishou.monitor.MessageThreadLocal;
import com.aihuishou.monitor.model.DefaultTransaction;
import lombok.extern.slf4j.Slf4j;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Slf4j
public class UrlLogFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;

        // 1、解析请求头、uri(延迟再校验一次)
        String name = req.getRequestURI();
        // 2、构建Transaction开始
        DefaultTransaction t = LogMonitor.newTransaction(LogConstants.TYPE_URL, name);

        try {
            // 打印Event
            this.logRequestClientInfo(req);
            this.logRequestPayload(req);
        } catch (Exception ignored) {
        }

        try {
            // 3、放行
            chain.doFilter(request, response);
            t.setStatus(LogConstants.SUCCESS);
        } catch (Exception ex) {
            t.setStatus(ex.getClass().getName());
            throw ex;
        } finally {
            try {
                // 4、再次获取uri验证
                String routePattern = (String) req.getAttribute(LogConstants.ROUTE_URI);
                if (routePattern != null && !routePattern.equals(name)) {
                    t.setName(routePattern);
                }

                // 5、消息状态处理，完成动作
                Exception bizError = MessageThreadLocal.getBizError();
                if (bizError != null) {
                    t.setStatus(bizError.getClass().getName());
                }
                t.complete();
                MessageThreadLocal.getContext().endMessage(t);
            } catch (Exception ex) {
                log.error("UrlLogFilter埋点错误", ex);
            }
        }
    }

    private void logRequestPayload(HttpServletRequest req) {
        StringBuilder sb = new StringBuilder(256);

        sb.append(req.getScheme().toUpperCase()).append('/');
        sb.append(req.getMethod()).append(' ').append(req.getRequestURI());

        String qs = req.getQueryString();

        if (qs != null) {
            sb.append('?').append(qs);
        }
        LogMonitor.logEvent(LogConstants.TYPE_URL_METHOD, req.getMethod(), sb.toString(), LogConstants.SUCCESS);
    }

    protected void logRequestClientInfo(HttpServletRequest req) {
        StringBuilder sb = new StringBuilder(1024);
        String ip;
        String ipForwarded = req.getHeader("x-forwarded-for");

        if (ipForwarded == null) {
            ip = req.getRemoteAddr();
        } else {
            ip = ipForwarded;
        }

        sb.append("IPS=").append(ip);
        sb.append("&VirtualIP=").append(req.getRemoteAddr());
        sb.append("&Server=").append(req.getServerName());
        sb.append("&Referer=").append(req.getHeader("referer"));
        sb.append("&Agent=").append(req.getHeader("user-agent"));

        LogMonitor.logEvent(LogConstants.TYPE_URL_SERVER, ip, sb.toString(), LogConstants.SUCCESS);
    }

}
